package com.pitaya.framework.common;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Encrypt {
	
	private static final Log log = LogFactory.getLog(Encrypt.class);

	private static String encryptToMD5OrSHA(String algorithm, String value) {
		byte[] digesta = (byte[]) null;
		try {
			MessageDigest alga = MessageDigest.getInstance(algorithm);
			alga.update(value.getBytes());
			digesta = alga.digest();
		}catch (NoSuchAlgorithmException e) {
			log.error(e.getMessage());
		}
		String rs = byte2hex(digesta);
		return rs;
	}

	public static String encryptToMD5(String value) {
		return encryptToMD5OrSHA("MD5", value);
	}

	public static String encryptToSHA(String value) {
		return encryptToMD5OrSHA("SHA-1", value);
	}

	public static SecretKey createSecretKey(String algorithm) {
		SecretKey deskey = null;
		try {
			KeyGenerator keygen = KeyGenerator.getInstance(algorithm);
			deskey = keygen.generateKey();
		} catch (NoSuchAlgorithmException e) {
			log.error(e.getMessage());
		}
		return deskey;
	}

	public static String encryptToDES(SecretKey key, String value) {
		String Algorithm = "DES";
		SecureRandom sr = new SecureRandom();
		byte[] cipherByte = (byte[]) null;
		try {
			Cipher c1 = Cipher.getInstance(Algorithm);
			c1.init(1, key, sr);
			cipherByte = c1.doFinal(value.getBytes());
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return byte2hex(cipherByte);
	}

	public static String decryptByDES(SecretKey key, String value) {
		String Algorithm = "DES";

		SecureRandom sr = new SecureRandom();
		byte[] cipherByte = (byte[]) null;
		try {
			Cipher c1 = Cipher.getInstance(Algorithm);
			c1.init(2, key, sr);
			cipherByte = c1.doFinal(hex2byte(value));
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		}
		return new String(cipherByte);
	}

	public static void createPairKey() {
		try {
			KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");
			SecureRandom random = new SecureRandom();
			random.setSeed(1000L);
			keygen.initialize(512, random);
			KeyPair keys = keygen.generateKeyPair();
			PublicKey pubkey = keys.getPublic();
			PrivateKey prikey = keys.getPrivate();
			doObjToFile("mykeys.bat", new Object[] { prikey, pubkey });
		} catch (NoSuchAlgorithmException e) {
			log.error(e.getMessage());
		}
	}

	public static void signToInfo(String info, String signfile) {
		PrivateKey myprikey = (PrivateKey) getObjFromFile("mykeys.bat", 1);
		PublicKey mypubkey = (PublicKey) getObjFromFile("mykeys.bat", 2);
		try {
			Signature signet = Signature.getInstance("DSA");
			signet.initSign(myprikey);
			signet.update(info.getBytes());
			byte[] signed = signet.sign();
			doObjToFile(signfile, new Object[] { signed, mypubkey, info });
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}

	public static boolean validateSign(String signfile) {
		PublicKey mypubkey = (PublicKey) getObjFromFile(signfile, 2);
		byte[] signed = (byte[]) getObjFromFile(signfile, 1);
		String info = (String) getObjFromFile(signfile, 3);
		try {
			Signature signetcheck = Signature.getInstance("DSA");
			signetcheck.initVerify(mypubkey);
			signetcheck.update(info.getBytes());
			return signetcheck.verify(signed);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return false;
	}

	public static String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
		}
		return hs.toUpperCase();
	}

	public static byte[] hex2byte(String hex) {
		byte[] ret = new byte[8];
		byte[] tmp = hex.getBytes();
		for (int i = 0; i < 8; i++) {
			ret[i] = uniteBytes(tmp[(i * 2)], tmp[(i * 2 + 1)]);
		}
		return ret;
	}
	
	public static byte uniteBytes(byte src0, byte src1) {
		byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 })).byteValue();
		_b0 = (byte) (_b0 << 4);
		byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 })).byteValue();
		byte ret = (byte) (_b0 ^ _b1);
		return ret;
	}

	public static void doObjToFile(String file, Object[] objs) {
		ObjectOutputStream oos = null;
		try {
			FileOutputStream fos = new FileOutputStream(file);
			oos = new ObjectOutputStream(fos);
			for (int i = 0; i < objs.length; i++) {
				oos.writeObject(objs[i]);
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			try {
				oos.close();
			} catch (IOException ioe) {
				log.error(ioe.getMessage());
			}
		} finally {
			try {
				oos.close();
			} catch (IOException e) {
				log.error(e.getMessage());
			}
		}
	}

	public static Object getObjFromFile(String file, int i) {
		ObjectInputStream ois = null;
		Object obj = null;
		try {
			FileInputStream fis = new FileInputStream(file);
			ois = new ObjectInputStream(fis);
			for(int j = 0; j < i; j++) {
				obj = ois.readObject();
			}
		}catch (Exception e) {
			e.printStackTrace();
			try {
				ois.close();
			}catch (IOException ioe) {
				log.error(ioe.getMessage());
			}
		}finally {
			try {
				ois.close();
			}catch (IOException e) {
				log.error(e.getMessage());
			}
		}
		return obj;
	}
}
